<?php

namespace app\common\service;

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;
use ba\Exception;
use OSS\Core\OssException;
use OSS\Credentials\StaticCredentialsProvider;
use OSS\OssClient;
use think\db\exception\PDOException;
use think\exception\ValidateException;

class OssService extends ApiService
{

    /**
     * oss桶
     * @var mixed
     */
    private mixed $bucket;
    /**
     * oss区域
     * @var mixed
     */
    private mixed $region;
    /**
     * cos accessKeyId
     * @var mixed
     */
    private mixed $accessKeyId;
    /**
     * oss accessKeySecret
     * @var mixed
     */
    private mixed $accessKeySecret;
    /**
     * oss endpoint
     * @var mixed
     */
    private mixed $endpoint;

    private string $roleArn;
    private string $roleSessionName;
    private string $domain;

    private string $type;

    public function __construct()
    {
        $this->bucket = env('OSS.OSS_BUCKET');
        $this->region = env('OSS.OSS_REGION');
        $this->accessKeyId = env('OSS.OSS_ACCESS_KEY_ID');
        $this->accessKeySecret = env('OSS.OSS_ACCESS_KEY_SECRET');
        $this->endpoint = env('OSS.OSS_ENDPOINT');
        $this->roleArn = env('OSS.OSS_ROLE_ARN');
        $this->roleSessionName = env('OSS.OSS_SESSION_NAME');
        $this->domain = env('OSS.OSS_DOMAIN');
        $this->type = 'aliyun';
    }

    public function getDomain()
    {
        return $this->domain;
    }

    /**
     * 获取cos配置
     * @return array
     */
    private function getConfig(): array|bool
    {
        $provider = new StaticCredentialsProvider(
            $this->accessKeyId,
            $this->accessKeySecret
        );
        return [
            "provider" => $provider,
            "endpoint" => $this->endpoint,
            "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
            "region" => $this->region
        ];
    }

    /**
     * 获取Oss客户端
     */
    public function getClient(): OssClient
    {
        $config = $this->getConfig();
        return new OssClient($config);
    }

    public function getObject($path)
    {
        $url = parse_url($path);
        $object = ltrim($url['path'], '/');
        try {
            $client = $this->getClient();
            $res = $client->getObject($this->bucket, $object);
        } catch (\Exception $e) {
            $this->setError($e->getMessage());
            return false;
        }
        return $res;
    }

    public function putObject($savePath, $filePath)
    {
        return $this->simpleUpload($savePath, $filePath);

        // // 使用分片最小分片大小为5M
        // $partSize = 50 * 1024 * 1024; // 50MB
        // // 获取文件大小
        // $fileSize = filesize($filePath);
        //
        // // 小文件直接使用普通上传
        // if ($fileSize <= $partSize) {
        //     return $this->simpleUpload($savePath, $filePath);
        // } else {
        //     return $this->shardingUpload($savePath, $filePath);
        // }
    }


    /**
     * 简单上传
     * @param $savePath
     * @param $filePath
     * @return false|mixed
     */
    public function simpleUpload($savePath, $filePath)
    {
        try {
            $client = $this->getClient();
            $res = $client->putObject($this->bucket, $savePath, $filePath);
            $res = $res['info']['url'];
        } catch (\Exception $e) {
            $this->setError($e->getMessage());
            return false;
        }
        return $res;
    }


    /**
     * 分片上传
     * @param $savePath
     * @param $filePath
     * @return false|mixed
     */
    public function shardingUpload($savePath, $filePath)
    {
        $ossClient = $this->getClient();
        try {
            $options = [
                OssClient::OSS_CHECK_MD5 => true,
                OssClient::OSS_PART_SIZE => 1,
            ];
            $res = $ossClient->multiuploadFile($this->bucket, $savePath, $filePath, $options);
        } catch (Exception|PDOException|ValidateException|OssException $e) {
            $this->setError($e->getMessage());
            return false;
        }
        return explode('?', $res['info']['url'])[0];
    }


    public function getType()
    {
        return $this->type;
    }

    public function getInfo()
    {
        return [
            'domain' => $this->domain,
            'bucket' => $this->bucket,
            'region' => "oss-" . $this->region,
        ];
    }

    public function getSts()
    {
        AlibabaCloud::accessKeyClient($this->accessKeyId, $this->accessKeySecret)
            ->regionId($this->region)
            ->asDefaultClient();

        try {
            // 创建STS请求。
            $result = Sts::v20150401()
                ->assumeRole()
                // 设置角色ARN。
                ->withRoleArn($this->roleArn)
                // 指定自定义角色会话名称，用来区分不同的令牌。
                ->withRoleSessionName($this->roleSessionName)
                // 指定STS临时访问凭证过期时间为3600秒。
                ->withDurationSeconds(3600)
                ->request();

            // 获取响应中的凭证信息。
            $credentials = $result['Credentials'];
        } catch (ClientException|ServerException $e) {
            $this->setError($e->getErrorMessage());
            return false;
        }
        return [
            'securityToken' => $credentials['SecurityToken'],
            'expiration' => $credentials['Expiration'],
            'accessKeySecret' => $credentials['AccessKeySecret'],
            'accessKeyId' => $credentials['AccessKeyId']
        ];


    }


}
